#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/regs-gpio.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/sched.h>
#include <linux/gpio.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/io.h>

struct irq_type
{
    int irq;
    char *name;
    int number;
};

unsigned int *addr;
static struct irq_type key_irq[] = 
{
    {IRQ_EINT0,"S1",0},
    {IRQ_EINT2,"S2",1},
    {IRQ_EINT3,"S3",2},
    {IRQ_EINT4,"S4",3},
};

static irqreturn_t key_handler(int irq,void *dev_id)
{
    unsigned int data = ioread32(addr);
    printk("<1> the read data is %d",data);
    struct irq_type *nirq = (struct irq_type *)(dev_id);
    switch(nirq->number)
    {
        case 0:
            printk("<1> the key 1 ");
            break;
        case 1:
            printk("<1> the key 2 ");
            break;
        case 2:
            printk("<1> the key 3 ");
            break;
        case 3:
            printk("<1> the key 4 ");
            break;
    }
    return 0;
}

/*file_operations结构体*/
/*驱动函数的设置*/
/*分别将前面的驱动函数设置进来*/
static struct file_operations fl2440_keys_fops =
{
    .owner = THIS_MODULE,
    .open = fl2440_keys_open, /*open()*/
    .release = fl2440_keys_close, /*release()*/
    .read = fl2440_keys_read, /*read()*/
    .poll = fl2440_keys_poll /*poll()*/
};

int key_init(void)
{
    addr = ioremap(0x56000064,4);
    int i;
    int ret;
    for(i = 0;i < 6 ;i ++)
    {
        ret = request_irq(key_irq[i].irq,key_handler,IRQ_TYPE_EDGE_RISING,key_irq[i].name,(void *)&(key_irq[i]));    
        if(ret)
            goto out;
        printk("<1>request irq %d",i);
    }
    
    return 0;
out:
    printk("<1>this is out of key_init!!!!!!!");
    //free_irq();
    return -1;
}

void key_exit()
{
    /*移除设备*/
    devfs_remove(DEVICE_NAME);

    /*注消设备驱动*/
    unregister_chrdev(KEY_MAJOR,DEVICE_NAME);
    printk("<1> exit of the module!!!!!!!!!!!");
}

/**********************fl2440_keys_close()*****************************/
static int fl2440_keys_close(struct inode *inode,struct file *file)
{
    int i; /*循环变量,要操作好几个按键*/

    /*for循环,对各个按键依此释放中断*/

    for(i = 0;i < sizeof(key_irqs)/sizeof(key_irqs[0]);i++)
    {
        /*使中断失效*/
       disable_irq(key_irqs[i].irq);

       /*释放资源*/
       free_irq(key_irqs[i].irq,(void *)&key_irqs[i]);
    }

    /*返回*/
    return 0;
}

module_init(my_key_init);
module_exit(my_key_exit);

MODULE_DESCRIPTION("S3C2410/S3C2440 key Driver"); /*描述信息*/
MODULE_AUTHOR("wangyijieonline@126.com");
MODULE_LICENSE("Dual BSD/GPL");
